﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Diagnostics;

namespace DimensionData.Data2
{
    public class DTree
    {
        public int Level { get; set; }
        public string Code { get; set; }
        public List<DTreeNode> Nodes { get; set; }
        public DCTable Table { get; set; }

        /// <summary>
        /// 维度树所悬挂的上一颗维度上的节点
        /// </summary>
        public DTreeNode ParentNode { get; set; }

        /// <summary>
        /// 平面化之后的数据行
        /// </summary>
        private List<DRow> _rows;

        public DTree(string code, int level)
        {
            this.Code = code;
            this.Level = level;
            Nodes = new List<DTreeNode>();
        }

        public void Relate(DTree tree)
        {
        }

        /// <summary>
        /// 在node的位置插入个节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="insertNode"></param>
        public void InsertBefore(DTreeNode node, DTreeNode insertNode)
        {
            for (int index = 0; index < Nodes.Count; index++)
            {
                if (Nodes[index] == node)
                {
                    Nodes.Insert(index, insertNode);
                    break;
                }
            }
        }

        /// <summary>
        /// 平面化
        /// </summary>
        /// <returns></returns>
        public DataTable Complanate()
        {
            DataTable table = new DataTable();
            DTreeNode[] lineNodes = new DTreeNode[Table.Tables.Count];
            for (int index = 0; index < lineNodes.Length; index++)
            {
                table.Columns.Add(string.Format("Level{0}", index));
                table.Columns.Add(string.Format("Code{0}", index));
                table.Columns.Add(string.Format("Name{0}", index));
            }
            
            Stack<DTreeNode> stack = new Stack<DTreeNode>();
            for (int index = Nodes.Count - 1; index >= 0; index--)
            {
                stack.Push(Nodes[index]);
            }

            while (stack.Count > 0)
            {
                DTreeNode node = stack.Pop();
                lineNodes[node.Tree.Level] = node;

                if (node.NextTree != null)
                {
                    for (int index = node.NextTree.Nodes.Count - 1; index >= 0; index--)
                    {
                        stack.Push(node.NextTree.Nodes[index]);
                    }
                }
                else
                {
                    string destLevelField = string.Format("Level{0}", node.Tree.Level);
                    string destCodeField = string.Format("Code{0}", node.Tree.Level);
                    string destNameField = string.Format("Name{0}", node.Tree.Level);
                    DataRow newRow = table.NewRow();
                    newRow[destLevelField] = node.Level;
                    newRow[destCodeField] = node.Code;
                    newRow[destNameField] = node.Name;
                    for (int treeIndex = node.Tree.Level - 1; treeIndex >= 0; treeIndex--)
                    {
                        string prevDestLevelField = string.Format("Level{0}", treeIndex);
                        string prevDestCodeField = string.Format("Code{0}", treeIndex);
                        string prevDestNameField = string.Format("Name{0}", treeIndex);
                        newRow[prevDestLevelField] = lineNodes[treeIndex].Level;
                        newRow[prevDestCodeField] = lineNodes[treeIndex].Code;
                        newRow[prevDestNameField] = lineNodes[treeIndex].Name;
                    }
                    table.Rows.Add(newRow);

                    for (int index = node.Nodes.Count - 1; index >= 0; index--)
                    {
                        stack.Push(node.Nodes[index]);
                    }
                }
            }


            return table;
        }

        public List<DRow> Complanate2()
        {
            List<DRow> rows = new List<DRow>();

            Stack<DTreeNode> stack = new Stack<DTreeNode>();
            for (int index = Nodes.Count - 1; index >= 0; index--)
            {
                //PushRoot(stack, Nodes[index]);
                stack.Push(Nodes[index]);
            }

            while (stack.Count > 0)
            {
                DTreeNode node = stack.Pop();
                if (node.NextTree != null)
                {
                    for (int index = node.Nodes.Count - 1; index >= 0; index--)
                    {
                        stack.Push(node.Nodes[index]);
                    }

                    for (int index = node.NextTree.Nodes.Count - 1; index >= 0; index--)
                    {
                        stack.Push(node.NextTree.Nodes[index]);
                    }
                }
                else
                {
                    DRow row = node.GetDRow();
                    rows.Add(row);
                }
            }

            return rows;
        }

        private void PushRoot(Stack<DTreeNode> stack, DTreeNode root)
        {
            for (int index = root.Nodes.Count - 1; index >= 0; index--)
            {
                stack.Push(root.Nodes[index]);
                PushRoot(stack, root.Nodes[index]);
            }
        }

        /// <summary>
        /// 根据路径获取节点
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public DTreeNode GetNode(string path)
        {
            string[] segments = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
            DTreeNode dTreeNode = GetNodeByCode(this, segments[0]); ;
            for (int index = 1; index < segments.Length; index++)
            {
                dTreeNode = GetNodeByCode(dTreeNode, segments[index]);
            }
            return dTreeNode;
        }

        public static DTreeNode GetNodeByCode(DTree dTree, string code)
        {
            DTreeNode dTreeNode = null;

            for (int index = 0; index < dTree.Nodes.Count; index++)
            {
                if (string.Equals(dTree.Nodes[index].Code, code))
                {
                    dTreeNode = dTree.Nodes[index];
                    break;
                }

                if (dTreeNode == null)
                {
                    dTreeNode = GetNodeByCode(dTree.Nodes[index], code);

                    if (dTreeNode != null)
                    {
                        break;
                    }
                }
            }

            return dTreeNode;
        }

        public static DTreeNode GetNodeByCode(DTreeNode pNode, string code)
        {
            DTreeNode dTreeNode = null;

            for (int index = 0; index < pNode.Nodes.Count; index++)
            {
                if (string.Equals(pNode.Nodes[index].Code, code))
                {
                    dTreeNode = pNode.Nodes[index];
                    break;
                }

                if (dTreeNode == null)
                {
                    dTreeNode = GetNodeByCode(pNode.Nodes[index], code);

                    if (dTreeNode != null)
                    {
                        break;
                    }
                }
            }

            return dTreeNode;
        }
    }
}
